package com.lzycug.utils;


import com.lzycug.model.Bank;
import org.apache.commons.configuration2.PropertiesConfiguration;
import org.apache.commons.configuration2.builder.fluent.Configurations;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.yaml.snakeyaml.Yaml;

import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Optional;
import java.util.Properties;

/**
 * 配置类读取工具类
 */
public class ConfigUtil {
    private ConfigUtil() {
    }

    private static final Logger log = LogManager.getLogger(ConfigUtil.class);

    private static final Properties properties = new Properties();

    // 静态代码块加载properties配置进内存
    static {
        InputStream inputStream = null;
        try {
            // 获取类加载器
            ClassLoader loader = Thread.currentThread().getContextClassLoader();

            // 读取properties到输入流
            inputStream = loader.getResourceAsStream("config.properties");
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("load properties error: {}", e.getMessage());
        } finally {
            try {
                if (ObjectUtils.isNotEmpty(inputStream)) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                log.error("close inputStream error: {}", e.getMessage());
            }
        }
    }

    /**
     * @param propertiesPath
     * @return
     * @desc 加载properties配置文件到Map
     */
    public static HashMap<String, String> loadConfig(String propertiesPath) throws Exception {
        if (propertiesPath == null || propertiesPath.length() == 0) {
            return null;
        }
        PropertiesConfiguration config = new Configurations().properties(propertiesPath);
        if (config.size() == 0) {
            return null;
        }
        HashMap<String, String> configMap = new HashMap<>();
        for (Iterator<String> iterator = config.getKeys(); iterator.hasNext(); ) {
            String key = iterator.next();
            String value = config.getString(key);
            if (value == null || value.length() == 0) {
                return null;
            }
            configMap.put(key, value);
        }
        return configMap;
    }

    /**
     * @param cls            范型对象Class
     * @param propertiesPath 文件地址
     * @param <T>
     * @return
     * @throws Exception
     * @desc 加载properties配置文件到范型对象
     */
    public static <T> T loadConfigBean(Class<T> cls, String propertiesPath) throws Exception {
        if (propertiesPath == null || propertiesPath.length() == 0) {
            return null;
        }
        PropertiesConfiguration configuration = new Configurations().properties(propertiesPath);
        if (configuration.size() == 0) {
            return null;
        }
        T t = (T) cls.newInstance();
        Field[] fields = t.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            Object value = configuration.get(field.getType(), field.getName());
            //获取不到的字段自动忽略
            if (value == null) {
                System.out.println(field.getType() + " " + field.getName() + "get configuration is null");
                continue;
            }
            field.set(t, value);
        }
        return t;
    }

    /**
     * 根据指定key获取config.properties的value
     *
     * @param propertiesName properties文件key
     * @return 对应的配置值
     */
    public static String getProperty(String propertiesName) {
        return properties.getProperty(propertiesName);
    }

    /**
     * 将yaml文件解析为对应的JavaBean
     *
     * @param fileName yaml文件
     * @param cls      javaBean class
     * @param <T>      泛型类
     * @return JavaBean对象
     */
    public static <T> Optional<T> parseFile(String fileName, Class<T> cls) {
        Optional<File> loadFile = loadFile(fileName);
        if (loadFile.isPresent()) {
            try (InputStream is = new FileInputStream(loadFile.get())) {
                return Optional.of(new Yaml().loadAs(is, cls));
            } catch (FileNotFoundException e) {
                log.error("file {} isn't exist", new File(fileName).getName());
            } catch (IOException e) {
                log.error("illegal file: {}", new File(fileName).getName());
            }
        }
        return Optional.empty();
    }

    private static Optional<File> loadFile(String file) {
        return Optional.ofNullable(ConfigUtil.class.getClassLoader())
                .map(loader -> loader.getResource(file))
                .map(url -> new File(url.getFile()));
    }
}